package com.netty.source_code.transport;

import com.netty.source_code.transport.common.OutMsgHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.FixedLengthFrameDecoder;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.logging.LoggingHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.StandardCharsets;

/**
 * @author xl-9527
 * @since 2025/7/13
 **/
public class CustomDecoder {

    private static final Logger log = LoggerFactory.getLogger(CustomDecoder.class);

    public static void main(String[] args) throws InterruptedException {
        final EventLoopGroup boss = new NioEventLoopGroup(1);
        final EventLoopGroup work = new NioEventLoopGroup(2);
        final ServerBootstrap serverBootstrap = new ServerBootstrap()
                .group(boss, work)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(final NioSocketChannel ch) throws Exception {
                        ch.pipeline()
                                .addLast("logging", new LoggingHandler())
                                .addLast("decode", new CustomFixedLengthFrameDecoder())
                                .addLast(new OutMsgHandler());
                    }
                });

        serverBootstrap.bind(8080).sync().addListener(
                future -> {
                    if (future.isSuccess()) {
                        log.info("启动成功");
                    }
                }
        ).sync();
    }

    public void runClient() throws InterruptedException {
        final Bootstrap client = new Bootstrap()
                .group(new NioEventLoopGroup(2))
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(final NioSocketChannel ch) throws Exception {
                        ch.pipeline()
                                .addLast(new CustomFixedLengthFrameDecoder())
                                .addLast(new LoggingHandler())
                                .addLast(new OutMsgHandler());
                    }
                });

        final Channel channel = client.connect("127.0.0.1", 8080).addListener(
                future -> {
                    if (future.isSuccess()) {
                        log.info("连接成功");
                    }
                }
        ).sync().channel();

        channel.write(Unpooled.copiedBuffer("hello world XL-9527".getBytes(StandardCharsets.UTF_8)));
        channel.write(Unpooled.copiedBuffer("hello world XL-9527".getBytes(StandardCharsets.UTF_8)));
        channel.writeAndFlush(Unpooled.copiedBuffer("hello world XL-9527".getBytes(StandardCharsets.UTF_8)));
        log.info("发送了消息");

        channel.close().sync().addListener((future -> {
            if (future.isSuccess()) {
                log.info("关闭成功");
            }
        }));
    }

    private static class CustomFixedLengthFrameDecoder extends FixedLengthFrameDecoder {

        /**
         * 这里会创建一个固定长度为 6 的帧解码器
         */
        public CustomFixedLengthFrameDecoder() {
            super(6);
        }
    }

    private static class CustomDelimiterBaseFrameDecoder extends DelimiterBasedFrameDecoder {

        /**
         * 这里会创建一个分隔符为 & 的帧解码器
         */
        public CustomDelimiterBaseFrameDecoder() {
            super(
                    10, true, false,
                    Unpooled.copiedBuffer("&".getBytes(StandardCharsets.UTF_8))
            );
        }
    }

    private static class CustomLengthFieldBaseFrameDecoder extends LengthFieldBasedFrameDecoder {

        /**
         * 这里会创建一个长度字段为 1024 的帧解码器
         */
        public CustomLengthFieldBaseFrameDecoder() {
            // 设计一个魔术：2 字节，协议版本号：1 字节，序列化算法：1 字节，报文类型：1 字节，状态：1 字节，保留字段：4 字节，数据长度：4 字节，内容：N 字节
            super(
                    1024, 10, 4, 0, 0, false
            );
        }
    }
}
